package org.daochong.lang;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.net.URLEncoder;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.regex.Pattern;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

class JSONValue {
	private JSONValue parent;
	private Map<String, Object> current;
	private String name;

	public Map<String, Object> getCurrent() {
		return current;
	}

	public String getName() {
		return name;
	}

	public JSONValue getParent() {
		return parent;
	}

	public void setCurrent(Map<String, Object> current) {
		this.current = current;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setParent(JSONValue parent) {
		this.parent = parent;
	}

}

class JSONXmlHandler extends DefaultHandler {
	Map<String, Object> root;
	private JSONValue parent = null;
	private JSONValue rootValue;

	public void characters(char[] ch, int start, int length) throws SAXException {
		String txt = new String(ch, start, length).trim();
		if (this.parent != null && !txt.equals(""))
			this.parent.getCurrent().put("#text", txt);
	}

	public void endDocument() throws SAXException {
		// 处理单个文本节点
		process(this.root);
	}

	public void endElement(String uri, String localName, String qName) throws SAXException {
		this.parent = this.parent.getParent();
	}

	public void endPrefixMapping(String prefix) throws SAXException {

	}

	public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {

	}

	@SuppressWarnings("unchecked")
	private void process(Map<String, Object> m) {
		for (String key : m.keySet()) {
			Object o = m.get(key);
			if (o instanceof Map) {
				Map<String, Object> map = (Map<String, Object>) o;
				if (map.size() == 1 && map.containsKey("#text")) {
					m.put(key, map.get("#text"));
				} else {
					for (String k : map.keySet()) {
						Object v = map.get(k);
						if (v instanceof Map) {
							process((Map<String, Object>) v);
						} else if (v instanceof List) {
							for (Object vv : (List<?>) v) {
								if (vv instanceof Map) {
									process((Map<String, Object>) vv);
								}
							}
						}
					}
				}
			} else if (o instanceof List) {
				for (Object v : (List<?>) o) {
					if (v instanceof Map) {
						process((Map<String, Object>) v);
					}
				}
			}
		}
	}

	public void processingInstruction(String target, String data) throws SAXException {

	}

	public void setDocumentLocator(Locator locator) {

	}

	public void skippedEntity(String name) throws SAXException {

	}

	public void startDocument() throws SAXException {
		this.root = new LinkedHashMap<String, Object>();
		this.root = Collections.synchronizedMap(this.root);
		rootValue = new JSONValue();
		rootValue.setCurrent(root);
	}

	@SuppressWarnings("unchecked")
	public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {

		Map<String, Object> current = new LinkedHashMap<String, Object>();
		if (this.parent == null) {
			this.root.put(qName, current);
			this.rootValue.setName(qName);
			this.parent = this.rootValue;
		} else {
			Object v = this.parent.getCurrent().get(qName);
			if (v != null) {
				if (v instanceof List) {
					((List<Object>) v).add(current);
				} else {
					List<Object> list = new ArrayList<Object>();
					list.add(v);
					list.add(current);
					this.parent.getCurrent().put(qName, list);
				}
			} else {
				this.parent.getCurrent().put(qName, current);
			}
		}

		for (int i = 0; i < atts.getLength(); i++) {
			current.put("@" + atts.getQName(i), atts.getValue(i));
		}

		JSONValue jv = new JSONValue();
		jv.setName(qName);
		jv.setCurrent(current);
		jv.setParent(this.parent);
		this.parent = jv;
	}

	public void startPrefixMapping(String prefix, String uri) throws SAXException {

	}

}

public class StringUtils {

	public final static int BUFFER_SIZE = 8192;

	private static final String COMMON_CHINESE = "\u7684\u4e00\u4e86\u662f\u6211\u4e0d\u5728\u4eba\u4eec\u6709\u6765\u4ed6\u8fd9\u4e0a\u7740\u4e2a\u5730\u5230\u5927\u91cc\u8bf4\u5c31\u53bb\u5b50\u5f97\u4e5f\u548c\u90a3\u8981\u4e0b\u770b\u5929\u65f6\u8fc7\u51fa\u5c0f\u4e48\u8d77\u4f60\u90fd\u628a\u597d\u8fd8\u591a\u6ca1\u4e3a\u53c8\u53ef\u5bb6\u5b66\u53ea\u4ee5\u4e3b\u4f1a\u6837\u5e74\u60f3\u751f\u540c\u8001\u4e2d\u5341\u4ece\u81ea\u9762\u524d\u5934\u9053\u5b83\u540e\u7136\u8d70\u5f88\u50cf\u89c1\u4e24\u7528\u5979\u56fd\u52a8\u8fdb\u6210\u56de\u4ec0\u8fb9\u4f5c\u5bf9\u5f00\u800c\u5df1\u4e9b\u73b0\u5c71\u6c11\u5019\u7ecf\u53d1\u5de5\u5411\u4e8b\u547d\u7ed9\u957f\u6c34\u51e0\u4e49\u4e09\u58f0\u4e8e\u9ad8\u624b\u77e5\u7406\u773c\u5fd7\u70b9\u5fc3\u6218\u4e8c\u95ee\u4f46\u8eab\u65b9\u5b9e\u5403\u505a\u53eb\u5f53\u4f4f\u542c\u9769\u6253\u5462\u771f\u5168\u624d\u56db\u5df2\u6240\u654c\u4e4b\u6700\u5149\u4ea7\u60c5\u8def\u5206\u603b\u6761\u767d\u8bdd\u4e1c\u5e2d\u6b21\u4eb2\u5982\u88ab\u82b1\u53e3\u653e\u513f\u5e38\u6c14\u4e94\u7b2c\u4f7f\u5199\u519b\u5427\u6587\u8fd0\u518d\u679c\u600e\u5b9a\u8bb8\u5feb\u660e\u884c\u56e0\u522b\u98de\u5916\u6811\u7269\u6d3b\u90e8\u95e8\u65e0\u5f80\u8239\u671b\u65b0\u5e26\u961f\u5148\u529b\u5b8c\u5374\u7ad9\u4ee3\u5458\u673a\u66f4\u4e5d\u60a8\u6bcf\u98ce\u7ea7\u8ddf\u7b11\u554a\u5b69\u4e07\u5c11\u76f4\u610f\u591c\u6bd4\u9636\u8fde\u8f66\u91cd\u4fbf\u6597\u9a6c\u54ea\u5316\u592a\u6307\u53d8\u793e\u4f3c\u58eb\u8005\u5e72\u77f3\u6ee1\u65e5\u51b3\u767e\u539f\u62ff\u7fa4\u7a76\u5404\u516d\u672c\u601d\u89e3\u7acb\u6cb3\u6751\u516b\u96be\u65e9\u8bba\u5417\u6839\u5171\u8ba9\u76f8\u7814\u4eca\u5176\u4e66\u5750\u63a5\u5e94\u5173\u4fe1\u89c9\u6b65\u53cd\u5904\u8bb0\u5c06\u5343\u627e\u4e89\u9886\u6216\u5e08\u7ed3\u5757\u8dd1\u8c01\u8349\u8d8a\u5b57\u52a0\u811a\u7d27\u7231\u7b49\u4e60\u9635\u6015\u6708\u9752\u534a\u706b\u6cd5\u9898\u5efa\u8d76\u4f4d\u5531\u6d77\u4e03\u5973\u4efb\u4ef6\u611f\u51c6\u5f20\u56e2\u5c4b\u79bb\u8272\u8138\u7247\u79d1\u5012\u775b\u5229\u4e16\u521a\u4e14\u7531\u9001\u5207\u661f\u5bfc\u665a\u8868\u591f\u6574\u8ba4\u54cd\u96ea\u6d41\u672a\u573a\u8be5\u5e76\u5e95\u6df1\u523b\u5e73\u4f1f\u5fd9\u63d0\u786e\u8fd1\u4eae\u8f7b\u8bb2\u519c\u53e4\u9ed1\u544a\u754c\u62c9\u540d\u5440\u571f\u6e05\u9633\u7167\u529e\u53f2\u6539\u5386\u8f6c\u753b\u9020\u5634\u6b64\u6cbb\u5317\u5fc5\u670d\u96e8\u7a7f\u5185\u8bc6\u9a8c\u4f20\u4e1a\u83dc\u722c\u7761\u5174\u5f62\u91cf\u54b1\u89c2\u82e6\u4f53\u4f17\u901a\u51b2\u5408\u7834\u53cb\u5ea6\u672f\u996d\u516c\u65c1\u623f\u6781\u5357\u67aa\u8bfb\u6c99\u5c81\u7ebf\u91ce\u575a\u7a7a\u6536\u7b97\u81f3\u653f\u57ce\u52b3\u843d\u94b1\u7279\u56f4\u5f1f\u80dc\u6559\u70ed\u5c55\u5305\u6b4c\u7c7b\u6e10\u5f3a\u6570\u4e61\u547c\u6027\u97f3\u7b54\u54e5\u9645\u65e7\u795e\u5ea7\u7ae0\u5e2e\u5566\u53d7\u7cfb\u4ee4\u8df3\u975e\u4f55\u725b\u53d6\u5165\u5cb8\u6562\u6389\u5ffd\u79cd\u88c5\u9876\u6025\u6797\u505c\u606f\u53e5\u533a\u8863\u822c\u62a5\u53f6\u538b\u6162\u53d4\u80cc\u7ec6";

	private static final char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e',
			'f' };

	private static final char[] legalChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
			.toCharArray();

	private static final Map<Integer, String> NUMBER_UPPERS = new HashMap<Integer, String>();

	static {
		NUMBER_UPPERS.put(0, "零");
		NUMBER_UPPERS.put(1, "壹");
		NUMBER_UPPERS.put(2, "贰");
		NUMBER_UPPERS.put(3, "叁");
		NUMBER_UPPERS.put(4, "肆");
		NUMBER_UPPERS.put(5, "伍");
		NUMBER_UPPERS.put(6, "陆");
		NUMBER_UPPERS.put(7, "柒");
		NUMBER_UPPERS.put(8, "捌");
		NUMBER_UPPERS.put(9, "玖");

		NUMBER_UPPERS.put(11, "元");
		NUMBER_UPPERS.put(12, "拾");
		NUMBER_UPPERS.put(13, "佰");
		NUMBER_UPPERS.put(14, "仟");
		NUMBER_UPPERS.put(15, "万");
		NUMBER_UPPERS.put(16, "拾");
		NUMBER_UPPERS.put(17, "佰");
		NUMBER_UPPERS.put(18, "仟");
		NUMBER_UPPERS.put(19, "亿");
		NUMBER_UPPERS.put(20, "拾");
		NUMBER_UPPERS.put(21, "佰");
		NUMBER_UPPERS.put(22, "仟");
	}

	private static int base64Decode(char c) {
		if (c >= 'A' && c <= 'Z') {
			return ((int) c) - 65;
		} else if (c >= 'a' && c <= 'z') {
			return ((int) c) - 97 + 26;
		} else if (c >= '0' && c <= '9') {
			return ((int) c) - 48 + 26 + 26;
		} else {
			switch (c) {
			case '+':
				return 62;
			case '/':
				return 63;
			case '=':
				return 0;
			default:
				throw new RuntimeException("unexpected code: " + c);
			}
		}
	}

	/**
	 * Decodes the given Base64 encoded String to a new byte array. The byte
	 * array holding the decoded data is returned.
	 */

	public static byte[] base64Decode(String s) {

		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		try {
			base64Decode(s, bos);
		} catch (IOException e) {
			throw new RuntimeException();
		}
		byte[] decodedBytes = bos.toByteArray();
		try {
			bos.close();
			bos = null;
		} catch (IOException ex) {
			System.err.println("Error while decoding BASE64: " + ex.toString());
		}
		return decodedBytes;
	}

	private static void base64Decode(String s, OutputStream os) throws IOException {
		int i = 0;

		int len = s.length();

		while (true) {
			while (i < len && s.charAt(i) <= ' ') {
				i++;
			}

			if (i == len) {
				break;
			}

			int tri = (base64Decode(s.charAt(i)) << 18) + (base64Decode(s.charAt(i + 1)) << 12)
					+ (base64Decode(s.charAt(i + 2)) << 6) + (base64Decode(s.charAt(i + 3)));

			os.write((tri >> 16) & 255);
			if (s.charAt(i + 2) == '=') {
				break;
			}
			os.write((tri >> 8) & 255);
			if (s.charAt(i + 3) == '=') {
				break;
			}
			os.write(tri & 255);

			i += 4;
		}
	}

	public static String base64Encode(byte[] data) {
		int start = 0;
		int len = data.length;
		StringBuffer buf = new StringBuffer(data.length * 3 / 2);

		int end = len - 3;
		int i = start;
		int n = 0;

		while (i <= end) {
			int d = ((((int) data[i]) & 0x0ff) << 16) | ((((int) data[i + 1]) & 0x0ff) << 8)
					| (((int) data[i + 2]) & 0x0ff);

			buf.append(legalChars[(d >> 18) & 63]);
			buf.append(legalChars[(d >> 12) & 63]);
			buf.append(legalChars[(d >> 6) & 63]);
			buf.append(legalChars[d & 63]);

			i += 3;

			if (n++ >= 18) {
				n = 0;
				buf.append("\r\n");
			}
		}

		if (i == start + len - 2) {
			int d = ((((int) data[i]) & 0x0ff) << 16) | ((((int) data[i + 1]) & 255) << 8);

			buf.append(legalChars[(d >> 18) & 63]);
			buf.append(legalChars[(d >> 12) & 63]);
			buf.append(legalChars[(d >> 6) & 63]);
			buf.append("=");
		} else if (i == start + len - 1) {
			int d = (((int) data[i]) & 0x0ff) << 16;

			buf.append(legalChars[(d >> 18) & 63]);
			buf.append(legalChars[(d >> 12) & 63]);
			buf.append("==");
		}

		return buf.toString();
	}

	public static byte[] compressZip(byte[] data) {
		return ZIPUtils.compressString(data);
	}

	public static String compressZip(String str) {
		return ZIPUtils.compressString(str);
	}

	public static byte[] decodeToBytes(int n) {
		return new byte[] { (byte) ((n >> 24) & 0xff), (byte) ((n >> 16) & 0xff), (byte) ((n >> 8) & 0xff),
				(byte) (n & 0xff) };
	}

	public static int decodeToUInt32(byte[] d) {
		return decodeToUInt32(d, 0);
	}

	public static int decodeToUInt32(byte[] d, int index) {
		int int_24 = (d[index++] << 24) & 0xff;
		int int_16 = (d[index++] << 16) & 0xff;
		int int_8 = (d[index++] << 8) & 0xff;
		int int_0 = d[index++] & 0xff;
		return int_24 + int_16 + int_8 + int_0;
	}

	public static byte[] decompressZip(byte[] data) {
		return ZIPUtils.decompressString(data);
	}

	public static String decompressZip(String str) {
		return ZIPUtils.decompressString(str);
	}

	public static byte[] decrptyAscii(byte[] data) {
		return decrptyAscii(data, 13);
	}

	public static byte[] decrptyAsciiCodes(int len) {
		int max = 126;
		byte[] tmp = new byte[95];
		for (int i = 32; i <= max; i++) {
			int t = i + len + i % len;
			if (t < 32 || t >= 127) {
				tmp[i - 32] = (byte) i;
				max = i - 1;
				break;
			}
			tmp[i - 32] = (byte) t;

		}
		int maxPos = 1;
		for (int i = 0; i < tmp.length; i++) {
			if (tmp[i] > max) {
				maxPos = i - 1;
				break;
			}
		}
		byte[] codes = new byte[maxPos + 1];
		for (int i = 0; i <= maxPos; i++) {
			int si = tmp[i];
			if (si > (maxPos + 32)) {
				si = (si - maxPos - 1);
			}
			codes[si - 32] = (byte) (i + 32);
		}
		return codes;
	}

	public static int asciiRandom() {
		int n = (int) (new Random().nextDouble() * 15 + 3);
		int deviation = n - (n % 2 == 0 ? 1 : 0);
		if (deviation == 7 || deviation == 9) {
			deviation = 11;
		}
		return deviation;
	}

	public static int asciiNext(int dev) {
		if (dev < 3 || dev > 17 || dev % 2 == 0)
			return dev;
		if (dev == 3) {
			return 5;
		} else if (dev == 5) {
			return 11;
		} else if (dev == 11) {
			return 13;
		} else if (dev == 13) {
			return 15;
		} else if (dev == 15) {
			return 17;
		}
		return dev;
	}

	public static byte[] decrptyAscii(byte[] data, int len) {
		byte[] re = new byte[data.length];
		byte[] codes = decrptyAsciiCodes(len);
		for (int i = 0; i < data.length; i++) {
			int p = data[i] - 32;
			if (p >= 0 && p < codes.length) {
				re[i] = codes[p];
			} else {
				re[i] = data[i];
			}
		}
		return re;
	}

	public static String decrptyAscii(String str) {
		return decrptyAscii(str, 13);
	}

	public static String decrptyAscii(String str, int len) {
		StringBuffer sb = new StringBuffer();
		int max = 0;
		for (max = 126; max > 0; max--) {
			if (max % len == (len - 1)) {
				break;
			}
		}
		max = max + len + max % len - 127 + 32;
		for (int i = 0; i < str.length(); i++) {
			int si = str.charAt(i);
			if (si < 32 || si > 126) {
				sb.append((char) si);
				continue;
			}
			if (si <= max) {
				si = si - 32 + 127;
			}
			int n = si % len;
			int r;
			if (n % 2 == 0) {
				r = si - len - n / 2;
			} else {
				r = si - len - (n + len) / 2;
			}
			sb.append((char) r);
		}
		return sb.toString();
	}

	public static String encodingUrl(String url) {
		return encodingUrl(url, "UTF-8");
	}

	public static String encodingUrl(String url, String encoding) {
		String root = "";
		String param = "";
		if (StringUtils.isEmpty(encoding)) {
			encoding = "UTF-8";
		}
		int pos = url.indexOf("?");
		String u = url;
		if (pos > 0) {
			param = url.substring(pos + 1);
			u = url.substring(0, pos);
		}

		if (url.startsWith("https://") || url.startsWith("http://") || url.startsWith("ftp://")) {
			pos = u.indexOf("/", 10);
			if (pos == -1)
				return url;
			root = u.substring(0, pos);
			u = u.substring(pos + 1);
		}
		String[] ar = u.split("/");
		try {
			for (int i = 0; i < ar.length - 1; i++) {
				root += "/" + URLEncoder.encode(ar[i], encoding);
			}

			root += "/" + ar[ar.length - 1];
			if (!StringUtils.isEmpty(param)) {
				param = param.replaceAll("&amp;", "@@&@@");
				ar = param.split("&");
				root += "?";
				for (int i = 0; i < ar.length; i++) {
					String str = ar[i];
					pos = str.indexOf("=");
					if (pos == -1) {
						root += URLEncoder.encode(str.replaceAll("@@&@@", "&amp;"), encoding);
					} else {
						root += URLEncoder.encode(str.substring(0, pos), encoding) + "="
								+ URLEncoder.encode(str.substring(pos + 1), encoding);
					}
					if (i < ar.length - 1) {
						root += "&";
					}
				}
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return root;
	}

	public static byte[] encrptyAscii(byte[] bytes) {
		return encrptyAscii(bytes, 13);
	}

	public static byte[] encrptyAsciiCodes(int len) {
		int max = 126;
		byte[] tmp = new byte[95];
		for (int i = 32; i <= max; i++) {
			int t = i + len + i % len;
			if (t < 32 || t >= 127) {
				tmp[i - 32] = (byte) i;
				max = i - 1;
				break;
			}
			tmp[i - 32] = (byte) t;

		}
		int maxPos = 1;
		for (int i = 0; i < tmp.length; i++) {
			if (tmp[i] > max) {
				maxPos = i - 1;
				break;
			}
		}
		byte[] codes = new byte[maxPos + 1];
		byte[] codes1 = new byte[maxPos + 1];
		for (int i = 0; i <= maxPos; i++) {
			int si = tmp[i];
			if (si > (maxPos + 32)) {
				si = (si - maxPos - 1);
			}
			codes[i] = (byte) si;
			codes1[si - 32] = (byte) (i + 32);
		}
		return codes;
	}

	public static byte[] encrptyAscii(byte[] bytes, int len) {
		byte[] re = new byte[bytes.length];
		byte[] codes = encrptyAsciiCodes(len);
		for (int i = 0; i < bytes.length; i++) {
			int pos = bytes[i] - 32;
			if (pos >= 0 && pos < codes.length) {
				re[i] = codes[pos];
			} else {
				re[i] = bytes[i];
			}
		}
		return re;
	}

	public static String encrptyAscii(String str) {
		return encrptyAscii(str, 13);
	}

	public static String encrptyAscii(String str, int len) {
		return new String(encrptyAscii(str.getBytes(), len));
	}

	public static String fileSize(double s) {
		String n = s + "B";
		if (s >= 1024 && s < 1024 * 1024) {
			n = Math.round(s * 100.0 / 1024) / 100.0 + "K";
		} else if (s >= 1024 * 1024 && s < 1024 * 1024 * 1024) {
			n = Math.round(s * 100.0 / 1024 / 1024) / 100.0 + "M";
		} else if (s >= 1024 * 1024 * 1024) {
			n = Math.round(s * 100.0 / 1024 / 1024 / 1024) / 100.0 + "G";
		} else if (s >= 1024 * 1024 * 1024 * 1024) {
			n = Math.round(s * 100.0 / 1024 / 1024 / 1024 / 1024) / 100.0 + "T";
		}
		return n;
	}

	public static String firstLowerCase(String s) {
		if (s == null)
			return null;
		String re = s.substring(1);
		int asc = s.charAt(0);
		if (asc >= 65 && asc <= 90)
			asc += 32;
		re = String.valueOf((char) asc) + re;
		return re;
	}

	public static String firstUpperCase(String s) {
		if (s == null)
			return null;
		String re = s.substring(1);
		int asc = s.charAt(0);
		if (asc >= 97 && asc <= 122)
			asc -= 32;
		re = String.valueOf((char) asc) + re;
		return re;
	}

	public static String getFileExt(String fileName) {
		int pos = fileName.lastIndexOf(".");
		if (pos > 0) {
			return fileName.substring(pos + 1);
		} else {
			return "";
		}
	}

	public static String getUrlPath(String path) {
		int pos = path.lastIndexOf("/");
		int p1 = path.lastIndexOf("?");
		if (p1 < pos) {
			return path;
		} else {
			return path.substring(0, p1);
		}
	}

	public static byte[] hexDecode(String dataStr) {
		/*
		 * if ((dataStr.length() & 1) == 1) dataStr = new String(dataStr + "0");
		 * BigInteger cI = new BigInteger(dataStr, 16); byte data[] =
		 * cI.toByteArray(); return data;
		 */

		byte[] res = new byte[dataStr.length() / 2];
		char[] chs = dataStr.toCharArray();
		for (int i = 0, c = 0; i < chs.length; i += 2, c++) {
			res[c] = (byte) (Integer.parseInt(new String(chs, i, 2), 16));
		}

		return res;
	}

	public static String hexEncode(byte dataStr[]) {
		return hexEncode(dataStr, 0, dataStr.length);
	}

	public static String hexEncode(byte dataStr[], int len) {
		return hexEncode(dataStr, 0, len);
	}

	public static String hexEncode(byte dataStr[], int start, int len) {
		StringWriter w = new StringWriter();
		for (int i = start; i < start + len; i++) {
			int b = dataStr[i];
			w.write(hex[b >> 4 & 0xf]);
			w.write(hex[b >> 0 & 0xf]);
		}
		return w.toString();
	}

	public static boolean isCommonChar(char ch) {
		return isCommonChar((int) ch);
	}

	public static boolean isCommonChar(int ch) {
		return (ch >= 48 && ch <= 57) || (ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122);
	}

	public static boolean isEmpty(String s) {
		return (s == null ? true : s.trim().equals(""));
	}

	public static boolean isIpAdresses(String ip) {
		try {
			String[] ar = ip.split("\\.");
			if (ar.length != 4)
				return false;
			int s1 = Integer.parseInt(ar[0]);
			if (s1 <= 0 || s1 > 255) {
				return false;
			}
			for (int i = 1; i < 4; i++) {
				int s = Integer.parseInt(ar[i]);
				if (s < 0 || s > 255)
					return false;
			}
			return true;
		} catch (Throwable e) {
			return false;
		}
	}

	public static void main(String[] args) {
		System.out.println(pathMatcher("/sql/**/*.*", "/sql/ddd/ddd/abbc.properties"));
		String pattern = "/sql/**/*.properties";
		pattern = "/sql/abbc.properties";
		String p = "";
		if (pattern.indexOf("**") >= 0) {
			String[] ar = pattern.split("\\*\\*");
			if (ar[0].equals("")) {
				p = ".*";
			} else {
				p = "(" + ar[0].replaceAll("\\.", "\\\\.") + ").*";
			}
			String last = ar[0];
			for (int i = 1; i < ar.length; i++) {
				p += "(" + ((last.length() > 0 && last.charAt(last.length() - 1) == ar[i].charAt(0))
						? ar[i].substring(1) : ar[i]).replaceAll("\\.", "\\\\.").replaceAll("\\*", "[^/\\\\\\\\]*")
						+ ")";
				last = ar[0];
				p += (i < ar.length - 1 ? ".*" : "");
			}
		} else {
			p = pattern.replaceAll("\\.", "\\\\.").replaceAll("\\*", "[^/\\\\\\\\]*");
		}
		System.out.println(p);
		System.out.println(Pattern.matches(p, "/sql/abbc.properties"));
	}

	public static String md5(byte[] data) {
		FileInputStream in = null;
		String value = "";
		try {
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			md5.update(data);
			BigInteger bi = new BigInteger(1, md5.digest());
			value = bi.toString(16);
		} catch (Exception e) {

		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return value;
	}

	public static String md5(File file) {
		FileInputStream in = null;
		String value = "";
		try {
			in = new FileInputStream(file);
			MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			md5.update(byteBuffer);
			BigInteger bi = new BigInteger(1, md5.digest());
			value = bi.toString(16);
		} catch (Exception e) {

		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return value;
	}

	public static String md5(String str) {
		try {
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			md5.update(str.getBytes());
			return hexEncode(md5.digest());
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);
		}
	}

	public static String numberToUpper(double d) {
		String str = String.valueOf((Math.round(d * 100)) / 100.0);
		int pos = str.indexOf('.');
		String en = "";
		if (pos >= 0) {
			en = str.substring(pos + 1);
			str = str.substring(0, pos);
		}

		String re = "";
		int len = str.length();
		for (int i = 0; i < len; i++) {
			int p = str.charAt(i) - 48;
			String t = "";
			if (p > 0) {
				t = NUMBER_UPPERS.get(p) + NUMBER_UPPERS.get(10 + len - i);
			} else {
				if ((len - i) % 4 == 1) {
					while (re.endsWith("零")) {
						re = re.substring(0, re.length() - 1);
					}
					t += NUMBER_UPPERS.get(10 + len - i);
				} else if (!re.endsWith("零")) {
					t = "零";
				}
			}
			re += t;
		}
		if (en.equals("")) {
			re += "整";
		} else {
			if (en.length() == 1) {
				re += NUMBER_UPPERS.get(en.charAt(0) - 48) + "角";
			} else if (en.length() == 2) {
				re += NUMBER_UPPERS.get(en.charAt(0) - 48) + "角" + NUMBER_UPPERS.get(en.charAt(1) - 48) + "分";
			}
		}

		return re;
	}

	public static void out(InputStream in, OutputStream out) {
		out(in, out, BUFFER_SIZE);
	}

	public static void out(InputStream in, OutputStream out, int bufferSize) {
		int len;
		byte[] buffer = new byte[bufferSize];
		try {
			while ((len = in.read(buffer)) != -1) {
				out.write(buffer, 0, len);
			}
		} catch (Throwable e) {
			throw new RuntimeException(e);
		}
	}

	public static boolean pathMatcher(String pattern, String target) {
		try {
			if (pattern.equals(target)) {
				return true;
			}
			String p = "";
			if (pattern.indexOf("**") >= 0) {
				String[] ar = pattern.split("\\*\\*");
				if (ar[0].equals("")) {
					p = ".*";
				} else {
					p = "(" + ar[0].replaceAll("\\.", "\\\\.") + ").*";
				}
				String last = ar[0];
				for (int i = 1; i < ar.length; i++) {
					p += "(" + ((last.length() > 0 && last.charAt(last.length() - 1) == ar[i].charAt(0))
							? ar[i].substring(1) : ar[i]).replaceAll("\\.", "\\\\.").replaceAll("\\*", "[^/\\\\\\\\]*")
							+ ")";
					last = ar[0];
					p += (i < ar.length - 1 ? ".*" : "");
				}
			} else {
				p = pattern.replaceAll("\\.", "\\\\.").replaceAll("\\*", "[^/\\\\\\\\]*");
			}
			return Pattern.matches(p, target);
		} catch (Throwable e) {
			e.printStackTrace();
		}
		return false;
	}

	public static String randomChar(int charCount) {
		if (charCount <= 0)
			return null;
		return randomChar(charCount, 1).get(0);
	}

	public static List<String> randomChar(int charCount, int count) {
		if (charCount <= 0 || count <= 0)
			return new ArrayList<String>();
		List<String> list = new ArrayList<String>(count);
		for (int i = 0; i < count; i++) {
			char[] ch = new char[charCount];
			for (int j = 0; j < charCount; j++) {
				Random r = new Random();
				boolean flag = ((int) (r.nextDouble() * 10)) % 2 == 0;
				if (flag) {
					r = new Random();
					int pos = (int) (Math.abs(r.nextDouble()) * 486 + 1);
					ch[j] = COMMON_CHINESE.charAt(pos);
				} else {
					r = new Random();
					int pos = (int) Math.abs(r.nextDouble() * 74) + 48;
					while (!isCommonChar(pos)) {
						pos = (int) Math.abs(r.nextDouble() * 74) + 48;
					}
					ch[j] = (char) pos;
				}
			}
			list.add(new String(ch));
		}
		return list;
	}

	public static String randomChinese(int chineseCount) {
		if (chineseCount <= 0)
			return null;
		return randomChinese(chineseCount, 1).get(0);
	}

	public static List<String> randomChinese(int chineseCount, int count) {
		if (chineseCount <= 0 || count <= 0)
			return new ArrayList<String>();
		List<String> list = new ArrayList<String>(count);
		for (int i = 0; i < count; i++) {
			char[] ch = new char[chineseCount];
			for (int j = 0; j < chineseCount; j++) {
				Random r = new Random();
				int pos = (int) (Math.abs(r.nextDouble()) * 486 + 1);
				ch[j] = COMMON_CHINESE.charAt(pos);
			}
			list.add(new String(ch));
		}
		return list;
	}

	public static String randomCommonChar(int charCount) {
		if (charCount <= 0)
			return null;
		return randomCommonChar(charCount, 1).get(0);
	}

	public static List<String> randomCommonChar(int charCount, int count) {
		if (charCount <= 0 || count <= 0)
			return new ArrayList<String>();
		List<String> list = new ArrayList<String>(count);
		for (int i = 0; i < count; i++) {
			char[] ch = new char[charCount];
			for (int j = 0; j < charCount; j++) {
				Random r = new Random();
				int pos = (int) Math.abs(r.nextDouble() * 74) + 48;
				while (!isCommonChar(pos)) {
					pos = (int) Math.abs(r.nextDouble() * 74) + 48;
				}
				ch[j] = (char) pos;
			}
			list.add(new String(ch));
		}
		return list;
	}

	public static String randomRangeChinese(int startCount, int endCount) {
		if (startCount <= 0 || endCount <= 0 || startCount > endCount)
			return null;
		return randomRangeChinese(startCount, endCount, 1).get(0);
	}

	public static List<String> randomRangeChinese(int startCount, int endCount, int count) {
		if (startCount <= 0 || endCount <= 0 || count <= 0 || startCount > endCount)
			return new ArrayList<String>();
		if (startCount == endCount)
			return randomChinese(startCount, count);
		List<String> list = new ArrayList<String>(count);
		for (int i = 0; i < count; i++) {
			Random r = new Random();
			int chineseCount = (int) (Math.abs(r.nextDouble() * (endCount - startCount + 1))) + startCount;
			char[] ch = new char[chineseCount];
			for (int j = 0; j < chineseCount; j++) {
				r = new Random();
				int pos = (int) (Math.abs(r.nextDouble()) * 486 + 1);
				ch[j] = COMMON_CHINESE.charAt(pos);
			}
			list.add(new String(ch));
		}
		return list;
	}

	public static String removeHtmlTag(String text) {
		try {
			int idx = text.indexOf("<");
			if (idx == -1) {
				return text;
			}

			String plainText = "";
			String htmlText = text;
			int htmlStartIndex = htmlText.indexOf("<", 0);
			if (htmlStartIndex == -1) {
				return text;
			}
			while (htmlStartIndex >= 0) {
				plainText += htmlText.substring(0, htmlStartIndex);
				int htmlEndIndex = htmlText.indexOf(">", htmlStartIndex);
				htmlText = htmlText.substring(htmlEndIndex + 1);
				htmlStartIndex = htmlText.indexOf("<", 0);
			}
			plainText = plainText.trim();
			return plainText;
		} catch (Exception e) {
			return text;
		}
	}

	public static boolean saveToFile(OutputStream out, byte[] content) {
		try {
			out.write(content);
			out.close();
			return true;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
	}

	public static boolean saveToFile(String path, byte[] content) {
		try {
			return saveToFile(new FileOutputStream(path), content);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return false;
		}
	}

	public static boolean saveToFile(String path, String content) {
		return saveToFile(path, content, null);
	}

	public static boolean saveToFile(String path, String content, String encode) {
		try {
			if (encode != null) {
				return saveToFile(new FileOutputStream(path), content.getBytes(encode));
			} else {
				return saveToFile(new FileOutputStream(path), content.getBytes());
			}
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	public static String sha1(byte[] data) {
		return new SHA1().getDigestOfString(data);
	}

	public static String sha1(File file) {
		FileInputStream in = null;
		String value = "";
		try {
			in = new FileInputStream(file);
			MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());
			MessageDigest sha1 = MessageDigest.getInstance("SHA1");
			sha1.update(byteBuffer);
			BigInteger bi = new BigInteger(1, sha1.digest());
			value = bi.toString(16);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return value;
	}

	public static String sizeName(long size) {
		if (size < 1000) {
			return size + "B";
		} else if (size < 1000000) {
			return Math.round(size * 100 / 1024.0) / 100.0 + "K";
		} else if (size < 1000000000) {
			return Math.round(size * 100 / 1024.0 / 1024.0) / 100.0 + "M";
		} else if (size < 1000000000000L) {
			return Math.round(size * 100 / 1024.0 / 1024.0 / 1024.0) / 100.0 + "G";
		} else {
			return "";
		}
	}

	public static byte[] toBytes(InputStream in) {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		byte[] re = null;
		try {
			out(in, bos);
			re = bos.toByteArray();
			bos.close();
			in.close();
		} catch (Throwable e) {
			throw new RuntimeException(e);
		}
		return re;
	}

	public static String toJSONString(Object obj) {
		StringBuffer sb = new StringBuffer();
		toJSONString(obj, sb);
		return sb.toString();
	}

	@SuppressWarnings("unchecked")
	private static void toJSONString(Object obj, StringBuffer sb) {
		if (obj instanceof String) {
			sb.append("\"" + ((String) obj) + "\"");
		} else if (obj instanceof Map) {
			toJSONStringMap((Map<String, Object>) obj, sb);
		} else if (obj instanceof List) {
			toJSONStringList((List<Object>) obj, sb);
		} else if (obj instanceof Object[]) {
			List<Object> list = Arrays.asList((Object[]) obj);
			toJSONStringList(list, sb);
		} else {
			toJSONStringMap(toMap(obj), sb);
		}
	}

	private static void toJSONStringList(List<Object> list, StringBuffer sb) {
		sb.append("[");
		int n = 0;
		for (Object o : list) {
			if (n++ > 0) {
				sb.append(",");
			}
			toJSONString(o, sb);
		}
		sb.append("]");
	}

	private static void toJSONStringMap(Map<String, Object> map, StringBuffer sb) {
		sb.append("{");
		int n = 0;
		for (String key : map.keySet()) {
			Object o = map.get(key);
			if (n++ > 0) {
				sb.append(",");
			}
			sb.append("\"" + key + "\":");
			toJSONString(o, sb);
		}
		sb.append("}");
	}

	private static Map<String, Object> toMap(Object obj) {
		Map<String, Object> map = new LinkedHashMap<String, Object>();
		Class<?> clazz = obj.getClass();
		for (Method method : clazz.getMethods()) {
			String name = method.getName();
			Class<?>[] c = method.getParameterTypes();
			if (name.startsWith("get") && (c == null || c.length == 0)) {
				try {
					map.put(name.substring(3), method.invoke(obj));
				} catch (Exception e) {

				}
			}
		}
		return map;
	}

	public static String toString(InputStream in) {
		return new String(toBytes(in));
	}

	public static String toString(InputStream in, Charset charset) {
		if (charset == null)
			return new String(toBytes(in));
		return new String(toBytes(in), charset);
	}

	public static String toString(InputStream in, String charset) {
		try {
			if (charset == null)
				return new String(toBytes(in));
			return new String(toBytes(in), charset);
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException(e);
		}
	}

	public static String toString(Throwable e) {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		PrintStream ps = new PrintStream(bos);
		e.printStackTrace(ps);
		String re = bos.toString();
		ps.close();
		try {
			bos.close();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		return re;
	}

	public static String utfDecode(String dataStr) {
		if (dataStr == null)
			return null;
		int start = 0;
		int len = dataStr.length();
		final StringBuffer buffer = new StringBuffer();
		start = dataStr.indexOf("\\u");
		if (start == -1)
			return dataStr;
		if (start > 0)
			buffer.append(dataStr.substring(0, start));
		int last = 0;
		while (start < len) {
			if (start == -1) {
				break;
			}
			if (start + 6 > len) {
				buffer.append(dataStr.substring(start));
				break;
			}
			try {
				char letter = (char) Integer.parseInt(dataStr.substring(start + 2, start + 6), 16);
				buffer.append(new Character(letter).toString());
				start = start + 6;
			} catch (Exception e) {
				buffer.append("\\u");
				start += 2;
			}
			last = start;
			start = dataStr.indexOf("\\u", start);
			if (start > last)
				buffer.append(dataStr.substring(last, start));
		}
		if (last < len)
			buffer.append(dataStr.substring(last));
		String re = new String(buffer);
		return re;
	}

	public static String utfEncode(String src) {
		if (src == null)
			return null;
		StringBuffer re = new StringBuffer();
		int code;
		for (int i = 0; i < src.length(); i++) {
			code = src.charAt(i);
			if (code > 255)
				re.append("\\u" + Integer.toHexString(code & 0xffff));
			else
				re.append((char) code);
		}
		return new String(re);
	}

	public static String value(String... values) {
		for (String value : values) {
			if (!isEmpty(value)) {
				return value;
			}
		}
		return null;
	}

	public static Map<String, Object> xmlToJSON(File file) {
		SAXParserFactory sf = SAXParserFactory.newInstance();
		JSONXmlHandler handler = new JSONXmlHandler();
		try {
			SAXParser sp = sf.newSAXParser();
			sp.parse(file, handler);
		} catch (Exception e) {
			e.printStackTrace();
		}

		return handler.root;
	}

	public static Map<String, Object> xmlToJSON(InputStream in) {
		SAXParserFactory sf = SAXParserFactory.newInstance();
		JSONXmlHandler handler = new JSONXmlHandler();
		try {
			SAXParser sp = sf.newSAXParser();
			sp.parse(in, handler);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return handler.root;
	}
};
